package ua.kiev.tosik.price.gui;

import org.apache.commons.lang.time.DurationFormatUtils;
import org.apache.log4j.Logger;
import ua.kiev.tosik.price.conf.AppConfig;
import ua.kiev.tosik.price.conf.Chapter;
import ua.kiev.tosik.price.conf.ChapterConfig;
import ua.kiev.tosik.price.conf.Language;
import ua.kiev.tosik.price.database.connectors.ConnectorFactory;
import ua.kiev.tosik.price.database.connectors.IConnector;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DecimalFormat;
import java.text.NumberFormat;


public class MainWindow {

	public static MainWindow ourInstance = null;
	private static Logger logger = Logger.getLogger(MainWindow.class);
	private JFrame frame;
	private Tray tray;
	private AppConfig config;

	public static MainWindow getInstance() {
		if ( ourInstance == null ) {
			ourInstance = new MainWindow();
		}
		return ourInstance;
	}

	public void show() {
		frame.setVisible(true);
	}

	private MainWindow() {
		logger.info("Initialize Main Window");
		config = AppConfig.getInstance();
		frame = createFrame();
		/**
		 * Auto start last module
		 */
		if ( !config.get("app.lasttab.class").equals("") ) {
			for ( final Chapter ch: ChapterConfig.getInstance().getChapterList() ) {
				if ( ch.getClassName().equals(config.get("app.lasttab.class")) ) {
					ChapterRunner.runChapter(ch);
					break;
				}
			}
		}
		tray = new Tray();
	}

	private JFrame createFrame() {
		frame = new JFrame();
		applyConfigToFrame();
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent ev) {
				exit();
			}
		});

		frame.setJMenuBar(MainMenu.getInstance().getMenuBar());
		frame.getContentPane().add(StatusBar.getInstance().getStatusBar(), BorderLayout.SOUTH);
		frame.getContentPane().add(TaskMenuPanel.getInstance().getTaskPanel(), BorderLayout.WEST);
		frame.getContentPane().add(CenterPanel.getInstance().getPanel(), BorderLayout.CENTER);
		return frame;
	}

	private void applyConfigToFrame() {
		frame.setIconImage(new ImageIcon(config.get("app.icon")).getImage());
		frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		frame.setSize(new Dimension(Integer.valueOf(config.get("app.width")), Integer.valueOf(config.get("app.height"))));
		if (config.get("app.maximize").equals("true")) {
			frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
		} else {
			if (!config.get("app.x").equals("") && !config.get("app.y").equals("")) {
				frame.setLocation(new Point(Integer.valueOf(config.get("app.x")), Integer.valueOf(config.get("app.y"))));
			} else {
				frame.setLocationRelativeTo(null);
			}
		}
		frame.setLayout(new BorderLayout());
		frame.setTitle( Language.getInstance().get("app.title") );
	}

	public void exit() {
		JCheckBox compressDb = new JCheckBox("Compress database");
		compressDb.setSelected( config.get("app.compressDatabase").equals("true") );
		int res = JOptionPane.YES_OPTION;
		try {
			Object[] params = {Language.getInstance().get("app.quit.query") + "?", compressDb};
			res = JOptionPane.showConfirmDialog(
				frame,
				params,
				Language.getInstance().get("app.quit.query") + "?",
				JOptionPane.YES_NO_OPTION,
				JOptionPane.PLAIN_MESSAGE,
				new ImageIcon(Language.getInstance().get("app.quit.query.icon"))
			);
		} catch (Exception e) {
			logger.warn(e.getLocalizedMessage());
		}
		if (res == JOptionPane.YES_OPTION) {
			logger.debug("Exiting application");
			if (frame.getExtendedState() == JFrame.MAXIMIZED_BOTH) {
				config.set("app.maximize", "true");
			} else {
				config.set("app.maximize", "false");
				if (!config.get("app.width").equals(String.valueOf(frame.getWidth()))) {
					logger.debug("Save new window width");
					config.set("app.width", String.valueOf(frame.getWidth()));
				}
				if (!config.get("app.height").equals(String.valueOf(frame.getHeight()))) {
					logger.debug("Save new window height");
					config.set("app.height", String.valueOf(frame.getHeight()));
				}
				if (!config.get("app.x").equals(String.valueOf((int) frame.getLocation().getX()))) {
					logger.debug("Save new window x position");
					config.set("app.x", String.valueOf((int) frame.getLocation().getX()));
				}
				if (!config.get("app.y").equals(String.valueOf((int) frame.getLocation().getY()))) {
					logger.debug("Save new window y position");
					config.set("app.y", String.valueOf((int) frame.getLocation().getY()));
				}
			}

			config.set("app.compressDatabase", (compressDb.isSelected())?"true":"false");

			try {
				IConnector db = ConnectorFactory.getInstance(AppConfig.getInstance().get("app.dbtype"));
				if ( compressDb.isSelected() ) {
					CompressDbWorker compressWorker = new CompressDbWorker(db);
					StatusBar.getInstance().setProgressMax(compressWorker.getPlanLength());
					StatusBar.getInstance().setProgressString(Language.getInstance().get("app.table.compress.text"));
					compressWorker.addPropertyChangeListener(StatusBar.getInstance());
					compressWorker.execute();
				} else {
					finalClose(db);
				}
			} catch (Exception e) {
				logger.warn(e.getLocalizedMessage());
			}
		}
	}

	private void finalClose(IConnector db) {
		try {
			db.close();
		} catch (Exception e) {
			logger.warn(e);
		}
		frame.setVisible(false);
		frame.dispose();
		tray.destroy();
		System.exit(0);
	}

	public JFrame getFrame() {
		return frame;
	}



	private class CompressDbWorker extends SwingWorker<Void, Void> {

		private IConnector connector;
		private NumberFormat numberFormat = new DecimalFormat("#,###");
		private String[] tables = {"CLIENTS", "PRICES", "PRICES_FILES"};
		private long startTime;

		protected CompressDbWorker(IConnector db) {
			super();
			this.connector = db;
			logger.debug("Database size before compressing: " + numberFormat.format(connector.getDatabaseSize()) + " Kb");
		}

		protected int getPlanLength() {
			return tables.length;
		}

		@Override
		protected Void doInBackground() throws Exception {
			startTime = System.currentTimeMillis();
			firePropertyChange("COMPRESS_START", null, Language.getInstance().get("app.table.compress.text"));
			for ( int i = 0; i < tables.length; i++ ) {
				connector.compressTables(tables[i]);
				firePropertyChange("COMPRESS_COUNT", null, i);
			}
			return null;
		}

		@Override
		protected void done() {
			super.done();
			firePropertyChange("COMPRESS_DONE", false, true);
			logger.debug("Database size after compressing: " + numberFormat.format(connector.getDatabaseSize()) + " Kb");
			logger.debug("Compressing database time: " + DurationFormatUtils.formatDuration(System.currentTimeMillis()-startTime, "s.S") + " sec");
			finalClose(connector);
		}
	}

}
